from multiprocessing import Process, Queue

from threading import Thread

from core.object import BarData, MessageData
from core.template import Template
from core.constant import *
from conf import conf
from tools.file_manager import gen_data_name
from module.logic_module.exchange_server.trade_server import TradeServer
from module.logic_module.exchange_server.data_server import HistoryData, LiveData, DataServer

import time
import pandas as pd


class Engine:
    def __init__(self, super_model):
        self.super_model = super_model
        # 根据不同的模式加载不同的交易模块
        self.trade_server: TradeServer = None  # 回测、仿真、实盘模式
        self.data_server: DataServer = None  # 实盘数据、历史数据模式
        self.template: Template = None  # 指向策略
        self.is_end = None  # 标记实时模式下是否结束
        self.q = None
        self.ori_data_dc: dict[str, pd.DataFrame] = None

        # 初始视图类变量数据及其实体类变量
        self.fighting_mode_ls = []
        self.draw_data_dc = {}

    def add_data_server(self, data_server):
        self.data_server = data_server(self)

    def set_is_end(self, is_end):
        self.data_server.is_end = is_end

    def node(self, node_dc: dict[str, BarData]):

        pass

    def base_bar(self, base_bar: BarData):

        pass

    def start(self):
        # support server的开始回调
        # # 数据已经加载
        # p = Process(target=self.start_process, args=(self.q,))
        # p.start()
        # self.start_process(self.q)
        # 创建线程，循环获取q中的数据，并更新至类属性
        thread = Thread(target=self.super_model.start_thread, args=(self.q, self.super_model.symbol_name))
        thread.start()
        pass

    def stop(self):
        # 数据服务停止，执行model端的停止逻辑
        self.is_end = True
        self.q.put(None)
        print("驱动引擎终止，已向通道（Queue）传入None值。")
        pass

    def loop(self):
        # 创建通道
        self.q = Queue()
        if conf.DataBridge.own_data_name.value not in self.super_model.data_name:
            data_path = self.super_model.master.file_manager.describe_all_dc[self.super_model.data_name].path
        else:
            data_path = conf.DataBridge.own_data_name.value
        # 把q关联到super_model
        if self.super_model.run_mode == DataFlowMode.Live.value:
            self.super_model.engine.add_data_server(LiveData)
            # 实时运行模式
            # 创建循环
            while True:
                is_normal = self.super_model.engine.monitor(data_path, is_traverse=False)
                if is_normal:
                    self.ori_data_dc = self.data_server.ori_data_dc
                    draw_data = self.ori_data_dc[self.super_model.symbol_name]
                    k_columns = []
                    for column in ["open", "high", "low", "close", "volume"]:
                        if column in draw_data.columns:
                            k_columns.append(column)
                        else:
                            raise ValueError(f"缺少K线关键字段{column}。")

                    self.draw_data_dc["draw_data_k"] = draw_data[k_columns + self.super_model.k_factor]
                    self.draw_data_dc["draw_data_vol"] = draw_data[["volume"] + self.super_model.vol_factor]
                    self.draw_data_dc["draw_data_factor_1"] = draw_data[self.super_model.factor_1]
                    self.draw_data_dc["draw_data_factor_2"] = draw_data[self.super_model.factor_2]
                    self.q.put(self.draw_data_dc)
                else:
                    pass
                if self.is_end:
                    break
                else:
                    time.sleep(conf.KChart.monitor_period.value.total_seconds())

        elif self.super_model.run_mode == DataFlowMode.His.value:
            self.add_data_server(HistoryData)
            self.monitor(data_path, is_traverse=False)
            # 历史数据运行模式
            # 实时数据、历史数据模式下的共有属性
            # 实时数据由message模块生成，并供K线图模块调用
            if self.super_model.start_time:
                start_time = pd.to_datetime(self.super_model.start_time)
            else:
                start_time = None
            if self.super_model.end_time:
                end_time = pd.to_datetime(self.super_model.end_time)
            else:
                end_time = None
            # 结合获得的参数进行逻辑运算
            self.ori_data_dc = self.data_server.ori_data_dc
            if start_time is None:
                draw_data = self.ori_data_dc[self.super_model.symbol_name]
            elif end_time is None:
                draw_data = self.ori_data_dc[self.super_model.symbol_name].loc[start_time:]
            else:
                draw_data = self.ori_data_dc[self.super_model.symbol_name].loc[start_time: end_time]

            k_columns = []
            for column in ["open", "high", "low", "close", "volume"]:
                if column in draw_data.columns:
                    k_columns.append(column)
                else:
                    raise ValueError(f"缺少K线关键字段{column}。")

            self.draw_data_dc["draw_data_k"] = draw_data[k_columns + self.super_model.k_factor]
            self.draw_data_dc["draw_data_vol"] = draw_data[["volume"] + self.super_model.vol_factor]
            self.draw_data_dc["draw_data_factor_1"] = draw_data[self.super_model.factor_1]
            self.draw_data_dc["draw_data_factor_2"] = draw_data[self.super_model.factor_2]
            self.q.put(self.draw_data_dc)
        else:
            pass

    def monitor(self, data_path, is_traverse):
        status = self.data_server.monitor(data_path, self.node, self.base_bar, is_traverse)
        return status


